﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Diagnostics;
using System.Web;
using System.Globalization;
using System.Collections.ObjectModel;

namespace Hallenberg.Web
{
    public class MemoryMembershipProvider : MembershipProvider
    {
        const string DefaultPassword = "start123";
        const int MaxInvalidPasswordAttemptsDefinition = 3;
        const int MinRequiredNonAlphanumericCharactersDefinition = 1;
        const int MinRequiredPasswordLengthDefinition = 5;
        const int PasswordAttemptWindowDefinition = 2;
        const string PasswordStrengthRegularExpressionDefinition = "";
        const bool RequiresQuestionAndAnswerDefinition = true;
        const bool RequiresUniqueEmailDefinition = true;

        private bool m_EnablePasswordReset;
        private bool m_EnablePasswordRetrieval;

        private List<MembershipUser> m_Users;

        public ReadOnlyCollection<MembershipUser> Users
        {
            get
            {
                return new ReadOnlyCollection<MembershipUser>(m_Users);
            }
        }

        public override string ApplicationName { get; set; }

        public override bool EnablePasswordReset
        {
            get { return m_EnablePasswordReset; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return m_EnablePasswordRetrieval; }
        }

        public MemoryMembershipProvider()
        {
            Reset();
        }

        public void Reset()
        {
            m_EnablePasswordReset = true;
            m_EnablePasswordRetrieval = true;

            m_Users = new List<MembershipUser>();
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            var userQuery = from user in this.Users
                            where user.UserName == username
                            select user;

            if (userQuery.Count() == 0)
            {
                return false;
            }

            MembershipUser foundUser = userQuery.First();

            return foundUser.ChangePassword(oldPassword, newPassword);
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            MembershipUser foundUser = this.GetUser(username, false);

            Debug.Assert(foundUser != null);
            if (foundUser == null)
            {
                return false;
            }

            return foundUser.ChangePasswordQuestionAndAnswer(password, newPasswordQuestion, newPasswordAnswer);
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            MembershipUser membershipUser = new MembershipUser(
                this.Name,
                username,
                Guid.NewGuid(),
                email,
                passwordQuestion,
                "No Comment",
                isApproved,
                false,
                DateTime.Now,
                DateTime.MinValue,
                DateTime.MinValue,
                DateTime.Now,
                DateTime.MinValue);

            membershipUser.SetPassword(password);
            membershipUser.SetPasswordAnswer(passwordAnswer);

            m_Users.Add(membershipUser);

            status = MembershipCreateStatus.Success;

            return membershipUser; ;
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            var userQuery = from user in this.Users
                            where user.UserName == username
                            select user;

            if (userQuery.Count() == 0)
            {
                return false;
            }

            MembershipUser foundUser = userQuery.First();
            if (!m_Users.Remove(foundUser))
            {
                return false;
            }

            Roles.RemoveUserFromRoles(username, Roles.GetRolesForUser(username));

            return true;
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            var userQuery = from user in this.Users
                            where user.Email.Contains(emailToMatch)
                            select user;

            pageIndex = 0;
            pageSize = 0;
            totalRecords = userQuery.Count();

            return userQuery.ToList().ToCollection();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection result = this.Users.Where(user => user.UserName.Contains(usernameToMatch)).ToList().ToCollection();

            totalRecords = result.Count;

            return result;

        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            pageIndex = 0;
            pageSize = 0;
            totalRecords = this.Users.Count;

            return m_Users.ToCollection();
        }

        public override int GetNumberOfUsersOnline()
        {
            return this.Users.Where(user => user.IsOnline).Count();
        }

        public override string GetPassword(string username, string answer)
        {
            var userQuery = from user in this.Users
                            where user.UserName == username
                            select user;

            Debug.Assert(userQuery.Count() > 0);

            if (userQuery.Count() == 0)
            {
                throw new InvalidOperationException("No such user");
            }

            MembershipUser foundUser = userQuery.First();
            return foundUser.GetPasswordFromMemory();
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            return this.Users.Where(u => u.UserName == username).First();
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            Debug.Assert(providerUserKey != null);
            if (providerUserKey == null)
            {
                throw new ArgumentNullException("providerUserKey");
            }

            return this.Users.FirstOrDefault(u => u.ProviderUserKey == providerUserKey && u.IsOnline == userIsOnline);
        }

        public override string GetUserNameByEmail(string email)
        {
            MembershipUser foundUser = this.Users.FirstOrDefault(user => user.Email == email);
            if (foundUser != null)
            {
                return foundUser.UserName;
            }

            return string.Empty;
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return MaxInvalidPasswordAttemptsDefinition; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return MinRequiredNonAlphanumericCharactersDefinition; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return MinRequiredPasswordLengthDefinition; }
        }

        public override int PasswordAttemptWindow
        {
            get { return PasswordAttemptWindowDefinition; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return MembershipPasswordFormat.Clear; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return PasswordStrengthRegularExpressionDefinition; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return RequiresQuestionAndAnswerDefinition; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return RequiresUniqueEmailDefinition; }
        }

        public override string ResetPassword(string username, string answer)
        {
            MembershipUser foundUser = this.Users.FirstOrDefault(user => user.UserName == username && user.GetLoweredPasswordAnswer() == answer.ToLower(CultureInfo.CurrentCulture));
            if (foundUser != null)
            {
                foundUser.SetPassword(DefaultPassword);
                return DefaultPassword;
            }

            return string.Empty;
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool ValidateUser(string username, string password)
        {
            return this.Users.Where(user => user.UserName == username && user.GetPassword() == password).Count() == 1;
        }

    }

}